// Package errors 是游戏服务器的错误处理扩展包，
// 基于标准库 errors 扩展，支持 gRPC 错误码、错误堆栈、错误链管理，
// 提供错误创建、解析、格式化等工具，适配服务器错误追踪与跨服务传递场景。
package errors

import (
	"errors"
	"fmt"
	"gameServer/core/stack"
	"io"

	"google.golang.org/grpc/codes" // 引入 gRPC 错误码类型，用于错误码标准化
)

// 预定义游戏服务器常用业务错误，覆盖网关、会话、连接、配置等核心场景，
// 所有错误均为标准 error 类型，可通过 Is() 方法判断匹配
var (
	ErrNil                   = New("nil")                         // 空错误（无效值场景）
	ErrInvalidGID            = New("invalid gate id")             // 无效网关ID（网关节点标识错误）
	ErrInvalidNID            = New("invalid node id")             // 无效节点ID（服务器节点标识错误）
	ErrInvalidMessage        = New("invalid message")             // 无效消息（消息格式/内容错误）
	ErrInvalidReader         = New("invalid reader")              // 无效读取器（IO 读取器初始化失败）
	ErrNotFoundSession       = New("not found session")           // 会话不存在（客户端会话未创建或已销毁）
	ErrInvalidSessionKind    = New("invalid session kind")        // 无效会话类型（会话类型不匹配业务需求）
	ErrReceiveTargetEmpty    = New("the receive target is empty") // 接收目标为空（消息发送时无目标地址）
	ErrInvalidArgument       = New("invalid argument")            // 无效参数（函数入参不符合校验规则）
	ErrNotFoundRoute         = New("not found route")             // 路由不存在（消息路由未注册）
	ErrNotFoundEvent         = New("not found event")             // 事件不存在（订阅的事件未定义）
	ErrNotFoundEndpoint      = New("not found endpoint")          // 端点不存在（服务端点未启动）
	ErrNotFoundUserLocation  = New("not found user's location")   // 用户位置不存在（未找到用户所在节点）
	ErrClientShut            = New("client is shut")              // 客户端已关闭（客户端主动断开连接）
	ErrConnectionOpened      = New("connection is opened")        // 连接已打开（重复创建连接）
	ErrConnectionHanged      = New("connection is hanged")        // 连接已挂起（连接处于临时不可用状态）
	ErrConnectionClosed      = New("connection is closed")        // 连接已关闭（连接被销毁）
	ErrConnectionNotOpened   = New("connection is not opened")    // 连接未打开（未初始化连接）
	ErrConnectionNotHanged   = New("connection is not hanged")    // 连接未挂起（操作需连接处于挂起状态）
	ErrTooManyConnection     = New("too many connection")         // 连接数过多（超出服务器连接上限）
	ErrSeqOverflow           = New("seq overflow")                // 序列号溢出（消息序列号超出范围）
	ErrRouteOverflow         = New("route overflow")              // 路由溢出（路由表条目超出上限）
	ErrMessageTooLarge       = New("message too large")           // 消息过大（超出协议规定的消息长度）
	ErrInvalidDecoder        = New("invalid decoder")             // 无效解码器（消息解码工具初始化失败）
	ErrInvalidScanner        = New("invalid scanner")             // 无效扫描器（数据扫描工具初始化失败）
	ErrNoOperationPermission = New("no operation permission")     // 无操作权限（用户无权限执行该操作）
	ErrInvalidConfigContent  = New("invalid config content")      // 无效配置内容（配置文件格式错误）
	ErrNotFoundConfigSource  = New("not found config source")     // 配置源不存在（未找到配置文件/服务）
	ErrInvalidFormat         = New("invalid format")              // 格式无效（数据格式不符合协议）
	ErrIllegalRequest        = New("illegal request")             // 非法请求（请求不符合业务规则）
	ErrIllegalOperation      = New("illegal operation")           // 非法操作（操作违反服务器约束）
	ErrInvalidPointer        = New("invalid pointer")             // 无效指针（空指针引用）
	ErrNotFoundLocator       = New("not found locator")           // 定位器不存在（服务定位工具未初始化）
	ErrUnexpectedEOF         = New("unexpected EOF")              // 意外EOF（数据读取提前结束）
	ErrMissTransporter       = New("miss transporter")            // 缺少传输器（消息传输工具未初始化）
	ErrMissDiscovery         = New("miss discovery")              // 缺少服务发现（服务发现工具未初始化）
	ErrNotFoundDirectAddress = New("not found direct address")    // 无直接地址（未找到服务直连地址）
	ErrUnknownError          = New("unknown error")               // 未知错误（未归类的错误）
	ErrClientClosed          = New("client is closed")            // 客户端已关闭（同 ErrClientShut，冗余定义兼容旧逻辑）
	ErrActorExists           = New("actor exists")                // Actor已存在（Actor模型实例重复创建）
	ErrMissDispatchStrategy  = New("missing dispatch strategy")   // 缺少分发策略（负载均衡/消息分发策略未配置）
	ErrUnregisterRoute       = New("unregistered route")          // 路由未注册（消息路由未注册到路由表）
	ErrNotBindActor          = New("not bind actor")              // 未绑定Actor（操作需绑定Actor实例）
	ErrNotFoundActor         = New("not found actor")             // Actor不存在（Actor实例未创建或已销毁）
	ErrWriterClosing         = New("writer is closing")           // 写入器正在关闭（写入操作时写入器处于关闭中）
)

// New 包装标准库 errors.New，创建基础错误（无错误码、无堆栈）
// 参数：
//
//	text: 错误描述文本
//
// 返回值：
//
//	error: 标准库 error 类型实例
func New(text string) error { return errors.New(text) }

// Is 包装标准库 errors.Is，判断错误是否与目标错误匹配（支持错误链）
// 参数：
//
//	err: 待判断的错误
//	target: 目标错误（如预定义的 ErrNotFoundSession）
//
// 返回值：
//
//	bool: 若 err 是 target 或包含 target，则返回 true，否则 false
func Is(err, target error) bool { return errors.Is(err, target) }

// As 包装标准库 errors.As，尝试将错误转换为目标类型（支持错误链）
// 参数：
//
//	err: 待转换的错误
//	target: 目标类型指针（如 &customErr）
//
// 返回值：
//
//	bool: 转换成功返回 true，否则 false
func As(err error, target any) bool { return errors.As(err, target) }

// Unwrap 包装标准库 errors.Unwrap，解包错误链的下一个错误
// 参数：
//
//	err: 待解包的错误
//
// 返回值：
//
//	error: 错误链中的下一个错误，若无则返回 nil
func Unwrap(err error) error { return errors.Unwrap(err) }

// NewError 创建自定义错误（支持绑定错误码、嵌套原始错误、错误描述）
// 参数：
//
//	args: 可变参数，支持三种类型：
//	      - error: 嵌套的原始错误（构成错误链）
//	      - string: 错误描述文本
//	      - *codes.Code: gRPC 错误码（如 codes.InvalidArgument）
//
// 返回值：
//
//	*Error: 自定义错误实例（包含 err、text、encoding 字段）
//
// 说明：参数顺序不影响，会自动根据类型赋值到对应字段
func NewError(args ...any) *Error {
	e := &Error{}

	for _, arg := range args {
		switch v := arg.(type) {
		case error:
			e.err = v // 嵌套原始错误
		case string:
			e.text = v // 错误描述文本
		case *codes.Code:
			e.code = v // 绑定 gRPC 错误码
		}
	}

	return e
}

// NewErrorWithStack 创建带堆栈的自定义错误（在 NewError 基础上增加堆栈追踪）
// 参数：
//
//	args: 同 NewError，支持 error、string、*codes.Code
//
// 返回值：
//
//	*Error: 带堆栈的自定义错误实例（stack 字段存储调用堆栈）
//
// 说明：stack.Callers(1, stack.Full) 表示从当前函数的上一层开始记录完整堆栈，便于定位错误发生位置
func NewErrorWithStack(args ...any) *Error {
	e := &Error{stack: stack.Callers(1, stack.Full)} // 初始化堆栈

	for _, arg := range args {
		switch v := arg.(type) {
		case error:
			e.err = v
		case string:
			e.text = v
		case *codes.Code:
			e.code = v
		}
	}

	return e
}

// GetErrCode 从错误中提取 gRPC 错误码
// 参数：
//
//	err: 待提取的错误（需实现 Code() *codes.Code 方法，如 *Error）
//
// 返回值：
//
//	*codes.Code: 提取到的错误码，若错误不支持则返回 nil
func GetErrCode(err error) *codes.Code {
	// 类型断言，这个是转换成对应接口，接口里面有一个方法，由于这里本来是一个正常结构体，实现这个方法以后可以使用
	if err != nil {
		// 类型断言：判断错误是否实现了 Code() 方法
		if e, ok := err.(interface{ Code() *codes.Code }); ok {
			return e.Code()
		}
	}
	// go的类型断言，可以用接口转换对应类型，前提是这个接口被类型实现了，也可以类型转接口，转过去以后还保留自己的方法实现
	return nil
}

// Next 获取错误链的下一个错误（即嵌套的原始错误）
// 参数：
//
//	err: 待处理的错误（需实现 Next() error 方法，如 *Error）
//
// 返回值：
//
//	error: 错误链的下一个错误，若无则返回 nil
func Next(err error) error {
	if err == nil {
		return nil
	}

	// 类型断言：判断错误是否实现了 Next() 方法
	if e, ok := err.(interface{ Next() error }); ok {
		return e.Next()
	}

	return nil
}

// Cause 获取错误链的根因错误（递归找到最底层的原始错误）
// 参数：
//
//	err: 待处理的错误（需实现 Cause() error 方法，如 *Error）
//
// 返回值：
//
//	error: 错误链的根因，若错误不支持则返回原错误
func Cause(err error) error {
	if err == nil {
		return nil
	}

	// 类型断言：判断错误是否实现了 Cause() 方法
	if e, ok := err.(interface{ Cause() error }); ok {
		return e.Cause()
	}

	return err
}

// Stack 从错误中提取堆栈信息
// 参数：
//
//	err: 待处理的错误（需实现 Stack() *stack.Stack 方法，如 *Error）
//
// 返回值：
//
//	*stack.Stack: 错误发生时的调用堆栈，若错误不支持则返回 nil
func Stack(err error) *stack.Stack {
	if err == nil {
		return nil
	}

	// 类型断言：判断错误是否实现了 Stack() 方法
	if e, ok := err.(interface{ Stack() *stack.Stack }); ok {
		return e.Stack()
	}

	return nil
}

// Replace 替换错误的描述文本（支持按错误码条件替换）
// 参数：
//
//	err: 待处理的错误（需实现 Replace 方法，如 *Error）
//	text: 新的错误描述文本
//	condition: 可选参数，错误码条件（仅当错误码匹配时才替换）
//
// 返回值：
//
//	error: 替换后的错误，若错误不支持则返回原错误
func Replace(err error, text string, condition ...codes.Code) error {
	if err == nil {
		return nil
	}

	// 类型断言：判断错误是否实现了 Replace 方法
	if e, ok := err.(interface {
		Replace(text string, condition ...codes.Code) error
	}); ok {
		return e.Replace(text, condition...)
	}

	return err
}

// Error 自定义错误结构体，实现 error 接口，支持：
// - 嵌套原始错误（err：构成错误链）
// - 自定义描述（text：业务相关错误描述）
// - gRPC 错误码（encoding：标准化错误码，用于跨服务传递）
// - 调用堆栈（stack：错误发生时的调用栈，用于定位）
type Error struct {
	err   error        // 嵌套的原始错误（错误链的下一个节点）
	text  string       // 错误描述文本
	code  *codes.Code  // gRPC 错误码（标准化错误类型）
	stack *stack.Stack // 错误堆栈（记录错误发生的代码位置）
}

// Error 实现 error 接口，返回完整错误描述（拼接错误码、描述、原始错误）
// 返回值：
//
//	text: 完整错误文本，格式优先级：错误码描述 > 自定义文本 > 原始错误描述
func (e *Error) Error() (text string) {
	if e == nil {
		return
	}

	// 1. 拼接错误码描述（若有且非成功码）
	if e.code != nil && *e.code != codes.OK {
		text = e.code.String()
	}

	// 2. 拼接自定义描述（若有）
	if e.text != "" {
		if text != "" {
			text += ": " // 已有内容时加分隔符
		}
		text += e.text
	}

	// 3. 拼接原始错误描述（若有）
	if e.err != nil && e.err.Error() != "" {
		if text != "" {
			text += ": "
		}
		text += e.err.Error()
	}

	return
}

// Code 返回错误绑定的 gRPC 错误码
// 返回值：
//
//	*codes.Code: 错误码指针，若未绑定则返回 nil
func (e *Error) Code() *codes.Code {
	if e == nil {
		return nil
	}

	return e.code
}

// Next 返回错误链的下一个错误（即嵌套的原始错误 err）
// 返回值：
//
//	error: 下一个错误，若无则返回 nil
func (e *Error) Next() error {
	if e == nil {
		return nil
	}

	return e.err
}

// Cause 递归获取错误链的根因错误（最底层的原始错误）
// 返回值：
//
//	error: 根因错误，若无嵌套错误则返回自身
func (e *Error) Cause() error {
	if e == nil {
		return nil
	}

	// 若没有嵌套错误，根因是自身
	if e.err == nil {
		return e
	}

	// 递归查找嵌套错误的根因
	cause := e.err
	for cause != nil {
		// 若嵌套错误实现了 Cause() 方法，继续深入
		if ce, ok := cause.(interface{ Cause() error }); ok {
			cause = ce.Cause()
		} else {
			break // 未实现则当前为根因
		}
	}

	return cause
}

// Stack 返回错误的调用堆栈
// 返回值：
//
//	*stack.Stack: 堆栈实例，若未记录堆栈则返回 nil
func (e *Error) Stack() *stack.Stack {
	if e == nil {
		return nil
	}

	return e.stack
}

// Unwrap 实现错误解包接口，返回嵌套的原始错误（同 Next()，兼容标准库 Unwrap）
// 返回值：
//
//	error: 嵌套的原始错误，若无则返回 nil
func (e *Error) Unwrap() error {
	if e == nil {
		return nil
	}

	return e.err
}

// Replace 替换错误的自定义描述文本（支持按错误码条件过滤）
// 参数：
//
//	text: 新的自定义描述文本
//	condition: 可选参数，错误码条件（仅当错误码与条件匹配时才替换）
//
// 返回值：
//
//	*Error: 替换后的错误实例（自身，非新创建）
func (e *Error) Replace(text string, condition ...*codes.Code) error {
	if e == nil {
		return nil
	}

	// 若无条件或条件匹配，替换文本
	if len(condition) == 0 || (len(condition) > 0 && condition[0] == e.code) {
		e.text = text
	}

	return e
}

// String 格式化错误信息，等价于 fmt.Sprintf("%+v", e)（调用 Format 方法）
// 返回值：
//
//	string: 包含完整错误链和堆栈的文本
func (e *Error) String() string {
	return fmt.Sprintf("%+v", e)
}

// error 内部辅助方法，返回本级错误的核心描述（不含嵌套错误）
// 返回值：
//
//	text: 核心描述，优先级：自定义文本 > 错误码描述
func (e *Error) error() (text string) {
	if e == nil {
		return
	}

	text = e.text
	// 若无自定义文本，使用错误码描述（非成功码）
	if text == "" && e.code != nil && *e.code != codes.OK {
		text = e.code.String()
	}

	return
}

// Format 实现 fmt.Formatter 接口，支持自定义格式化输出
// 支持的格式化动词：
//
//	%s: 仅输出本级错误的核心描述（调用 error() 方法）
//	%v: 输出完整错误描述（调用 Error() 方法，含错误链）
//	%+v: 输出完整错误链 + 每个错误的堆栈信息（用于详细日志排查）
func (e *Error) Format(s fmt.State, verb rune) {
	if e == nil {
		return
	}

	switch verb {
	case 'v':
		// 处理 %v（普通）和 %+v（带+标志，显示堆栈）
		if s.Flag('+') {
			var (
				i    int       // 错误链索引
				next error = e // 错误链当前节点
			)

			// 先输出完整错误描述，再打印堆栈
			io.WriteString(s, e.Error()+"\nStack:\n")
			for next != nil {
				i++
				// 判断当前错误是否为自定义 Error 类型
				if n, ok := next.(*Error); ok {
					// 输出本级错误索引和核心描述
					fmt.Fprintf(s, "%d. %s\n", i, n.error())
					// 输出本级错误的堆栈帧（函数名、文件名、行号）
					for frameIdx, f := range n.stack.Frames() {
						fmt.Fprintf(s, "\t%d). %s\n\t%s:%d\n",
							frameIdx+1, // 堆栈帧索引（从1开始）
							f.Function, // 函数名
							f.File,     // 文件名
							f.Line,     // 行号
						)
					}
					next = n.Next() // 进入错误链下一个节点
				} else {
					// 非自定义 Error 类型，输出错误描述后终止
					fmt.Fprintf(s, "%d. %s\n", i, next.Error())
					break
				}
			}
		} else {
			// 无 + 标志，仅输出完整错误描述（不含堆栈）
			io.WriteString(s, e.Error())
		}
	case 's':
		// 处理 %s，输出本级核心描述
		io.WriteString(s, e.error())
	}
}
